package com.codeduck.guava.collections;

import com.google.common.collect.*;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;

/**
 * 不可变集合(Immutable Collections): 防御性编程，持续收集，提高效率。
 * - 参考：https://github.com/google/guava/wiki/ImmutableCollectionsExplained
 *
 * @author: <a href="mailto:codeduck@163.com">Codeduck</a>
 * @createDate: 2022-05-19
 */
public class Demo01 {

    /**
     * Why Immutable Collections
     *
     * Immutable objects have many advantages, including:
     *
     * - 不受信任的库可以安全使用。
     * - 线程安全：可以被许多线程使用，没有竞争条件的风险。
     * - 不需要支持突变，并且可以通过该假设节省时间和空间。所有不可变集合实现都比它们的可变兄弟更节省内存。
     * - 可以用作常数，期望它保持不变。
     *
     * The JDK provides Collections.unmodifiableXXX methods, but in our opinion, these can be
     *
     * - 笨拙且冗长；在你想制作防御性副本的任何地方使用都不愉快
     * - 不安全：只有在没有人持有对原始集合的引用时，返回的集合才是真正不可变的
     * - 低效：数据结构仍然具有可变集合的所有开销，包括并发修改检查、哈希表中的额外空间等。
     */
    public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
            "red",
            "orange",
            "yellow",
            "green",
            "blue",
            "purple");

    public static void main(String[] args) {

        // for example
        final ImmutableSet<String> bars;
        bars = ImmutableSet.copyOf(COLOR_NAMES);
        System.out.println(bars.size());


        /**
         *  An ImmutableXXX collection can be created in several ways:
         */
        ImmutableSet.copyOf(new HashSet<Integer>());
        ImmutableSet.of("a", "b", "c");
        ImmutableMap.of("a", 1, "b", 2);
        ImmutableList.copyOf(new ArrayList<Integer>());
        // etc.

        // using a Builder
        HashSet<Color> WEBSAFE_COLORS = new HashSet<>();
        ImmutableSet<Color> COLORS  = ImmutableSet.<Color>builder()
                .addAll(WEBSAFE_COLORS)
                .add(new Color(0, 191, 255))
                .build();

    }

    static class Color {
        private int R;
        private int G;
        private int B;

        public Color(int r, int g, int b) {
            R = r;
            G = g;
            B = b;
        }
    }
}
